package com.hzgj.bcl.stats;

import lombok.Getter;

import java.util.concurrent.atomic.AtomicLong;

public class TimeFlowCounter extends TimeCounter {

    @Getter
    private final AtomicLong threshold;
    private final long minuteSpan;
    private final FlowOverListener flowOverListener;

    public TimeFlowCounter(long minuteSpan, FlowOverListener flowOverListener) {
        super();
        this.threshold = new AtomicLong(0);
        this.minuteSpan = minuteSpan;
        this.flowOverListener = flowOverListener;
    }

    @Override
    public void update(long span, long time) {
        if (span < 0) {
            return;
        }
        checkThreshold(time);
        if (Long.compare(Integer.MAX_VALUE, span) == 0) {
            return;
        }
        super.update(span, time);
    }


    private void checkThreshold(long time) {
        long target = getNearestTargetByMinuteSpan(time, minuteSpan);
        if (threshold.get() <= 0) {
            threshold.set(target);
        } else {
            if (Long.compare(target, threshold.get()) > 0) {
                long[] span = span(threshold.get(), target);
                if (span != null) {
                    for (int i = 0; i < span.length; i++) {
                        flowOverListener.call(metric, span[i]);
                    }
                }
                threshold.set(target);
            }
        }
    }

    private long[] span(long start, long end) {
        long value = end - start;
        if (value < 0) {
            return null;
        }
        int count = (int) (value / (minuteSpan * oneMinute));
        if (count == 0) {
            return null;
        }
        long[] result = new long[count];
        result[0] = start;
        for (int i = 1; i < count; i++) {
            result[i] = start + i * minuteSpan * oneMinute;
        }
        return result;
    }

    @Override
    public void clean() {
        lockForRescale();
        try {
            super.clean();
        } finally {
            unlockForRescale();
        }
    }

    public interface FlowOverListener {
        void call(Metric metric, long time);
    }
}
